from typing import Optional, Dict, Any, List
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, delete
from fastapi import HTTPException, status

from modules.system.models.role import Role
from modules.system.models.role_permission import RolePermission
from modules.system.schemas.role_schemas import RoleCreate, RoleUpdate
from modules.system.params.role_params import RoleQuery
from modules.system.curd.role_curd import role_dao
from utils.query_builder import build_select_stmt
from core.pagination import paging_data, _CustomPageParams


class RoleService:
    @staticmethod
    async def get_role_by_id(db: AsyncSession, role_id: int) -> Optional[Role]:
        return await role_dao.get_by_id(db, role_id)

    @staticmethod
    async def get_role_by_name(db: AsyncSession, name: str) -> Optional[Role]:
        return await role_dao.get_by_name(db, name)

    @staticmethod
    async def get_roles_with_pagination(db: AsyncSession, query_params: RoleQuery) -> Dict[str, Any]:
        # 使用通用查询构建器与分页封装
        stmt = build_select_stmt(
            Role,
            query_params,
            text_like_fields={"name", "desc"},
            keyword_fields={"name", "desc"},
        )
        stmt = stmt.order_by(Role.id.asc())
        params = _CustomPageParams(page=query_params.page, size=query_params.size)
        page_data = await paging_data(db, stmt, params=params)
        # 对齐返回结构：pages 字段与移除不必要的 links
        page_data["pages"] = page_data.get("total_pages", 0)
        page_data.pop("links", None)
        return page_data

    @staticmethod
    async def create_role(db: AsyncSession, payload: RoleCreate) -> Role:
        # 唯一性检查
        if await RoleService.get_role_by_name(db, payload.name):
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="角色名称已存在")
        # 使用仓储创建，服务层负责提交与刷新
        role = await role_dao.create(db, payload)
        await db.commit()
        await db.refresh(role)
        return role

    @staticmethod
    async def update_role(db: AsyncSession, role_id: int, payload: RoleUpdate) -> Role:
        # 先查存在
        exist_role = await RoleService.get_role_by_id(db, role_id)
        if not exist_role:
            raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="角色不存在")
        # 名称唯一性校验
        if payload.name and payload.name != exist_role.name:
            check = await RoleService.get_role_by_name(db, payload.name)
            if check and check.id != role_id:
                raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="角色名称已存在")
        # 使用仓储更新
        role = await role_dao.update(db, role_id, payload)
        await db.commit()
        if role:
            await db.refresh(role)
        return role

    @staticmethod
    async def delete_role(db: AsyncSession, role_id: int) -> None:
        role = await RoleService.get_role_by_id(db, role_id)
        if not role:
            raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="角色不存在")
        # 使用仓储删除；根据模型外键策略处理级联
        await role_dao.delete(db, role_id)
        await db.commit()

    @staticmethod
    async def get_role_permissions(db: AsyncSession, role_id: int) -> List[int]:
        # 查询角色的权限ID列表
        res = await db.execute(select(RolePermission.permission_id).where(RolePermission.role_id == role_id))
        ids = [row[0] for row in res.all()]
        return ids

    @staticmethod
    async def update_role_permissions(db: AsyncSession, role_id: int, permission_ids: List[int]) -> List[int]:
        # 先清空现有权限
        await db.execute(delete(RolePermission).where(RolePermission.role_id == role_id))
        # 批量插入新权限
        for pid in permission_ids:
            db.add(RolePermission(role_id=role_id, permission_id=pid))
        await db.flush()
        # 提交事务以确保权限更新持久化
        await db.commit()
        return permission_ids